package com.account.book.service.impl;

import com.account.book.common.context.UserTokenContextHolder;
import com.account.book.common.exception.BasicInfoException;
import com.account.book.common.exception.BasicInfoStatusEnum;
import com.account.book.entity.*;
import com.account.book.enums.*;
import com.account.book.mapper.BookMapper;
import com.account.book.mapper.BookUserMapper;
import com.account.book.request.BookQueryReqVo;
import com.account.book.response.BookResVo;
import com.account.book.response.BookUserQueryVo;
import com.account.book.response.BookUserResVo;
import com.account.book.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liang-hw
 * @className BookServiceImpl
 * @description 账本表 服务实现类
 * @date 2023/11/09 10:12:35
 */
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {

    private static final Logger logger = LoggerFactory.getLogger(BookServiceImpl.class);
    @Autowired
    private BookUserService bookUserService;

    @Autowired
    private UserService userService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private CategoryBaseService categoryBaseService;

    @Autowired
    private BookMapper bookMapper;

    @Autowired
    private BookUserMapper bookUserMapper;

    @Autowired
    private BookMoneyService bookMoneyService;

    @Autowired
    private MapperFacade mapperFacade;

    @Override
    @Transactional
    public void add(BookQueryReqVo bookQueryReqVo) {
        String userId = UserTokenContextHolder.getUserTokenVOByToken().getUserId();
        if (userId == null) {
            throw new BasicInfoException(BasicInfoStatusEnum.NO_AUTH.getCode(),
                    "请登录");
        }
        User userInfo = userService.getById(userId);
        if (userInfo == null) {
            throw new BasicInfoException(BasicInfoStatusEnum.NO_AUTH.getCode(),
                    "用户不存在");
        }
        // 如果是默认账本
        if (bookQueryReqVo.getDefaultBook().intValue() == 1) {
            QueryWrapper<BookUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(BookUser::getUserId, userId)
                    .ne(BookUser::getAuditStatus, BookUserAuditStatusEnum.REJECT.getValue())
                    .eq(BookUser::getStatus, DataStatusEnum.ENABLE.getValue());
            List<BookUser> list = bookUserService.list(queryWrapper);
            // 将该用户下的账本全部置为非默认账本
            list.stream().forEach(x -> x.setDefaultBook(BookDefaultEnum.IS_NOT_DEFAULT.getValue()));
            bookUserService.updateBatchById(list);
        }
        Book book = new Book();
        //拷贝
        BeanUtils.copyProperties(bookQueryReqVo, book);
        // 设置创建时间+创建人
        book.setCreateTime(new Date());
        book.setCreateBy(userId);
        book.setStatus(DataStatusEnum.ENABLE.getValue());
        this.save(book);
        // 添加自身账本用户外键关系
        BookUser bookUser = new BookUser();
        bookUser.setCreateBy(userId);
        bookUser.setCreateTime(new Date());
        bookUser.setAuth(BookAuthEnum.ROOT.getValue());
        bookUser.setStatus(DataStatusEnum.ENABLE.getValue());
        bookUser.setAuditStatus(BookUserAuditStatusEnum.DEFAULT.getValue());
        bookUser.setDefaultBook(bookQueryReqVo.getDefaultBook());
        bookUser.setUserId(userId);
        bookUser.setBookId(book.getId());
        bookUser.setAvatarUrl(StringUtils.isNotBlank(userInfo.getAvatarUrl()) ? userInfo.getAvatarUrl() : "");
        bookUser.setUserName(userInfo.getNickName());
        bookUser.setReallyName(userInfo.getNickName());
        bookUser.setBudget(bookQueryReqVo.getBudget());
        bookUserService.save(bookUser);
        // 新增默认分类
        List<CategoryBase> list = categoryBaseService.list(new QueryWrapper<CategoryBase>().lambda().eq(CategoryBase::getStatus, CategoryBaseEnum.ENABLE.getValue()));
        List<Category> collect = list.stream().map(x -> {
            Category category = new Category();
            BeanUtils.copyProperties(x, category, "id");
            category.setCategoryId(x.getId());
            category.setBookId(book.getId());
            category.setCreateBy(userId);
            category.setCreateTime(new Date());
            return category;
        }).collect(Collectors.toList());
        categoryService.saveBatch(collect);
    }

    @Override
    @Transactional
    public void update(BookQueryReqVo bookQueryReqVo, String userId) {
        Book dbBook = this.getById(bookQueryReqVo.getId());
        // 判断是否是账本管理员
        BookUserQueryVo bookUserQueryVo = bookUserService.isBookAuthor(dbBook.getId(), userId);
        if (ObjectUtils.isEmpty(bookUserQueryVo)) {
            logger.error("用户：{}无权操作账本", userId);
            throw new BasicInfoException(BasicInfoStatusEnum.NO_AUTH.getCode(),
                    "您无账本权限");
        }
        BeanUtils.copyProperties(bookQueryReqVo, dbBook, "created_time", "created_by", "status");
        dbBook.setUpdateBy(userId);
        this.updateById(dbBook);

        BookUser bookUser = new BookUser();
        bookUser.setDefaultBook(bookQueryReqVo.getDefaultBook());
        bookUser.setUpdateBy(userId);
        bookUser.setBudget(bookQueryReqVo.getBudget());
        bookUserService.update(bookUser, new QueryWrapper<BookUser>().lambda()
                .eq(BookUser::getBookId, dbBook.getId())
                .eq(BookUser::getUserId, userId));

        //更新账本用户信息
        if (bookQueryReqVo.getDefaultBook() == BookDefaultEnum.IS_DEFAULT.getValue()) {
            //其他账本为非默认
            UpdateWrapper<BookUser> wrapper = new UpdateWrapper<>();
            wrapper.lambda().ne(BookUser::getBookId, dbBook.getId())
                    .ne(BookUser::getAuditStatus, BookUserAuditStatusEnum.REJECT.getValue())
                    .eq(BookUser::getUserId, userId)
                    .eq(BookUser::getStatus, DataStatusEnum.ENABLE.getValue())
                    .set(BookUser::getDefaultBook, BookDefaultEnum.IS_NOT_DEFAULT.getValue());
            bookUserService.update(null, wrapper);
        }
    }

    /**
     * @param
     * @return @return {@link List }<{@link BookResVo }>
     * @author liang-hw
     * @description 查询我的账本
     * @date 2024/01/10 10:08:57
     */
    @Override
    public List<BookResVo> getBook() {
        String userId = UserTokenContextHolder.getUserTokenVOByToken().getUserId();
        List<BookUser> bookUserList = bookUserService.list(new QueryWrapper<BookUser>().lambda()
                .eq(BookUser::getStatus, DataStatusEnum.ENABLE.getValue())
                .ne(BookUser::getStatus, BookUserAuditStatusEnum.REJECT.getValue())
                .eq(BookUser::getUserId, userId).orderByDesc(BookUser::getDefaultBook));
        if (bookUserList.size() == 0) {
            return null;
        }
        //将List转换List
        List<String> bookIds = bookUserList.stream().map(BookUser::getBookId).collect(Collectors.toList());
        //将List转换Map
        Map<String, BigDecimal> bigDecimalMap = bookUserList.stream().collect(Collectors.toMap(BookUser::getBookId, p -> p.getBudget() == null ? new BigDecimal(0) : p.getBudget()));
        List<Book> bookList = this.list(new QueryWrapper<Book>().lambda()
                .eq(Book::getStatus, DataStatusEnum.ENABLE.getValue())
                .in(Book::getId, bookIds)
                .orderByDesc(Book::getCreateTime));
        //list拷贝
        List<BookResVo> bookResVoList = mapperFacade.mapAsList(bookList, BookResVo.class);
        String defaultBookId;
        //sql排了序，第一条肯定是默认账本
        if (bookUserList.get(0).getDefaultBook() == 1) {
            defaultBookId = bookUserList.get(0).getBookId();
        } else {
            defaultBookId = "";
        }
        // 设置默认值（因为没有左连接查询（懒得写sql了）bookUser表的 default_book字段）
        bookResVoList.stream().forEach(x -> {
            try {
                x.setBudget(bigDecimalMap.get(x.getId()));
                BookUserResVo bookUserResVo = bookUserService.getBookUser(x.getId());
                x.setBookUserResVo(bookUserResVo);
            } catch (BasicInfoException basicInfoException) {
                logger.error("异常信息：{}", basicInfoException.getMessage());
            }
            if (x.getId().equals(defaultBookId)) {
                x.setDefaultBook(BookDefaultEnum.IS_DEFAULT.getValue());
            } else {
                x.setDefaultBook(BookDefaultEnum.IS_NOT_DEFAULT.getValue());
            }
        });
        return bookResVoList.stream().sorted(Comparator.comparing(BookResVo::getDefaultBook).reversed()).collect(Collectors.toList());
    }


    /**
     * @param @param bookId
     * @param userId
     * @return
     * @author liang-hw
     * @description 删除账本
     * @date 2024/01/10 15:50:26
     */
    @Override
    @Transactional
    public void delete(String bookId, String userId) {
        // 判断是否是群主
        BookUser one = bookUserService.getOne(new QueryWrapper<BookUser>().lambda()
                .eq(BookUser::getBookId, bookId)
                .eq(BookUser::getUserId, userId)
                .eq(BookUser::getStatus, DataStatusEnum.ENABLE.getValue())
                .eq(BookUser::getAuth, BookAuthEnum.ROOT.getValue()));
        if (null == one) {
            logger.error("用户：{}无权操作账本", userId);
            throw new BasicInfoException(BasicInfoStatusEnum.NO_AUTH.getCode(),
                    "您无账本权限");
        }
        // 逻辑删除账本信息
        UpdateWrapper<Book> bookUpdateWrapper = new UpdateWrapper<>();
        bookUpdateWrapper.lambda().eq(Book::getId, bookId)
                .set(Book::getStatus, DataStatusEnum.DELETE.getValue());
        this.update(null, bookUpdateWrapper);

        // 删除用户信息
        UpdateWrapper<BookUser> bookUserUpdateWrapper = new UpdateWrapper<>();
        bookUserUpdateWrapper.lambda().eq(BookUser::getBookId, bookId)
                .set(BookUser::getStatus, DataStatusEnum.DELETE.getValue());
        bookUserService.update(null, bookUserUpdateWrapper);
        // 删除金额
        UpdateWrapper<BookMoney> bookMoneyUpdateWrapper = new UpdateWrapper<>();
        bookMoneyUpdateWrapper.lambda().eq(BookMoney::getBookId, bookId)
                .set(BookMoney::getStatus, DataStatusEnum.DELETE.getValue());
        bookMoneyService.update(null, bookMoneyUpdateWrapper);
    }

    /**
     * @param @param bookId
     * @param userId
     * @return @return {@link Long }
     * @author liang-hw
     * @description 判断当前用户是否是账本成员
     * @date 2024/01/16 19:16:51
     */
    @Override
    public Long isBookMember(String bookId, String userId) {
        Long aLong = bookUserMapper.selectCount((new QueryWrapper<BookUser>()).lambda()
                .eq(BookUser::getUserId, userId)
                .eq(BookUser::getBookId, bookId)
                .eq(BookUser::getStatus, DataStatusEnum.ENABLE.getValue()));
        return aLong;
    }

    /**
     * 用户加入账本
     *
     * @param bookId
     */
    @Override
    public BookResVo userAddBook(String bookId, String remark, String userId) {
        Book book = bookMapper.selectById(bookId);
        BookResVo bookResVo = new BookResVo();
        if (null == book) {
            logger.error("账本不存在，账本id：{}", bookId);
            throw new BasicInfoException(BasicInfoStatusEnum.SYSTEM_ERROR.getCode(),
                    "账本不存在");
        }
        // 默认真是姓名是微信名称
        User user = userService.getOne(new QueryWrapper<User>().lambda()
                .eq(User::getId, userId));
        if (null == user) {
            logger.error("加入账本失败，用户：{} 不存在", userId);
            throw new BasicInfoException(BasicInfoStatusEnum.NO_AUTH.getCode(),
                    "用户不存在");
        }
        // 为什么不能加 .eq(BookUser::getStatus,DataStatusEnum.ENABLE.getValue())条件，因为待审核的用户也需要调用该接口
        BookUser bookUser = bookUserService.getOne(new QueryWrapper<BookUser>().lambda()
                .eq(BookUser::getBookId, bookId)
                .eq(BookUser::getUserId, userId));
        // 用户存在默认账本 则为非默认账本，否则为默认账本
        List<BookUser> list = bookUserService.list(new QueryWrapper<BookUser>().lambda()
                .eq(BookUser::getDefaultBook, 1L)
                .eq(BookUser::getUserId, userId));
        BookUser bookUserOne = new BookUser();
        bookUserOne.setBookId(bookId);
        bookUserOne.setUserId(userId);
        bookUserOne.setRemark(remark);
        bookUserOne.setAuditStatus(BookUserAuditStatusEnum.DEFAULT.getValue());
        bookUserOne.setStatus(BookAuditEnum.ADMIN.getValue().equals(book.getUserAudit()) ? 2 : 1);
        bookUserOne.setAuth(BookAuthEnum.USER.getValue());
        bookUserOne.setDefaultBook(list.size() > 0 ? BookDefaultEnum.IS_NOT_DEFAULT.getValue() : BookDefaultEnum.IS_DEFAULT.getValue());
        bookUserOne.setUserName(user.getNickName());
        bookUserOne.setReallyName(user.getNickName());
        bookUserOne.setAvatarUrl(user.getAvatarUrl());
        bookUserOne.setCreateBy(userId);
        bookUserOne.setCreateTime(new Date());
        if (bookUser == null) {
            bookUserService.save(bookUserOne);
            //  需要审核
            if (BookAuditEnum.ADMIN.getValue().equals(book.getUserAudit())) {
                logger.warn("用户申请加入账本,用户id：{}", userId);
                bookResVo.setCode(201);
                bookResVo.setDesc("申请提交成功");
                return bookResVo;
            }
            return bookResVo;
        }

        bookUser.setAuditStatus(BookUserAuditStatusEnum.DEFAULT.getValue());
        bookUser.setStatus(BookAuditEnum.ADMIN.getValue().equals(book.getUserAudit()) ? 2 : 1);
        bookUser.setDefaultBook(list.size() > 0 ? BookDefaultEnum.IS_NOT_DEFAULT.getValue() : BookDefaultEnum.IS_DEFAULT.getValue());
        bookUser.setUpdateBy(userId);
        bookUser.setRemark(remark);
        bookUserService.updateById(bookUser);
        //  需要审核
        if (BookAuditEnum.ADMIN.getValue().equals(book.getUserAudit())) {
            bookResVo.setCode(201);
            bookResVo.setDesc("申请提交成功");
            return bookResVo;
        }
        return bookResVo;
    }

    @Override
    public List<BookResVo> searchBook(String bookName) {

        List<Book> bookList = this.list(new QueryWrapper<Book>().lambda()
                .eq(Book::getStatus, DataStatusEnum.ENABLE.getValue())
                .eq(Book::getShowSearch, BookSearchEnum.YES.getValue())
                .like(Book::getBookName, bookName)
                .orderByDesc(Book::getCreateTime));
        List<BookResVo> bookResVoList = mapperFacade.mapAsList(bookList, BookResVo.class);
        return bookResVoList;
    }
}
